home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / ScreenSavers / BackSpaceViews / StarShipView.BackModule / Celestial.bproj / Celestial.m < prev    next >
Encoding:
Text File  |  1995-06-12  |  8.1 KB  |  387 lines

  1. #import "Celestial.h"
  2. #import "TiffManager.h"
  3. #import "Thinker.h"
  4. #import <appkit/NXBitmapImageRep.h>
  5. #define PI (3.141592653589)
  6. #define MAXMULTBODY 10                //total multiple objects allowed
  7.  
  8. @implementation Celestial
  9.  
  10. - init
  11. {
  12.         [super init];
  13.         tiffStorageIndex = 0;
  14.         animationIndex = 0;
  15.  
  16.         tiffManagerObject = [[TiffManager alloc] init];
  17.         tiffStorage = [tiffManagerObject returnTiffStorage];
  18.         
  19.         bodyList = [[List alloc] init];
  20.             
  21.         avoidStorage = [[Storage allocFromZone:[self zone]] initCount:0
  22.          elementSize:sizeof(AvoidStruct) description:"{ffff}"];
  23.  
  24.         okToDoAnim = NO;
  25.         currentBodyIndex = 0;
  26.         cycleStartIndex = 0;
  27.         cycles = 0;
  28.         currentCycle = 1;
  29.         bodyCount = 0;
  30.         tiffsNeedBuilding = YES;
  31.         okToDoAnim = NO;
  32.         multDelay = floor(randBetween(objectSpeed * 0.1,
  33.          (objectSpeed * 0.1) + 10));
  34.         currentMultTotal = 1;
  35.         [starsObject setStarsStopped];
  36.         PSsetlinewidth(4.0);  //0.0 is more efficient but I liked this better
  37.             
  38.     return self;
  39.     
  40. }
  41. // Every module should have a first state method
  42. //since class info only gets loaded once - therefore only 1 init called
  43.  
  44. - setFirstState
  45. {
  46.     firstState = YES;
  47.     okToDoAnim = NO;
  48.     cycleStartIndex = currentBodyIndex;
  49.  
  50.     bodyCount = 0;
  51.     tiffsNeedBuilding = YES;
  52.     okToDoAnim = NO;
  53.     multDelay = floor(randBetween(objectSpeed * 0.1,
  54.         (objectSpeed * 0.1) + 10));
  55.     
  56.     
  57.     
  58.     currentMultTotal = 1;
  59.     starsStopping = NO; //[starsObject isStopping];  //should be NO
  60.     starsStopped = NO; //[starsObject isStopped]; //should be NO
  61.  
  62.     bodiesDone = 0;
  63.     currentCycle = 1;
  64.     
  65.     return self;
  66. }
  67. - (BOOL)doUntilDone
  68. {
  69. BOOL done;
  70. int ii,count;
  71.  
  72. done = NO;
  73.     
  74. if(!starsStopping){
  75.  
  76.     if(!okToDoAnim){ //go build the tiffs
  77.         if(tiffsNeedBuilding){
  78.             tiffsNeedBuilding = [tiffManagerObject createTiffs];
  79.         }
  80.         else { //do the animation set up
  81.                 totalBodies = [tiffStorage count];
  82.                 animBuilt = (MAXANIMATIONS > totalBodies) ? totalBodies :
  83.                  MAXANIMATIONS;  //pick smaller
  84.                 [self changeBodyList:currentBodyIndex];
  85.                 if(soundEnabled)
  86.                     [pwrUpSnd play];
  87.                 [starsObject startStars]; 
  88.                 starsStopping = NO; //[starsObject isStopping];  //should be NO
  89.                 starsStopped = NO; //[starsObject isStopped]; //should be NO
  90.                 okToDoAnim = YES;
  91.         }
  92.     }  //now do the animation
  93.     else {
  94.         if(nextStartTime < 0){ //time to do animation
  95.             count = [bodyList count];
  96.             multDelay--;
  97.             if(multDelay < 0){ // reset delay timer for next multiple object
  98.                 currentMultTotal++;
  99.                 if(currentMultTotal > count)
  100.                     currentMultTotal = count;
  101.                 multDelay = floor(randBetween(objectSpeed * 0.1,
  102.                  (objectSpeed * 0.1) + 10));
  103.                 
  104.             }
  105.             if(count){ // there are some objects to do
  106.                 for(ii = 0;ii < currentMultTotal;ii++){
  107.                     currentBody = [bodyList objectAt:ii];
  108.                     if([currentBody doUntilDone]){
  109.                         [bodyList removeObjectAt:ii];
  110.                         ii--;
  111.                         currentMultTotal--;
  112.                         currentBody = [currentBody free];
  113.                     }
  114.                 }
  115.             [starsObject setAvoidRect:avoidStorage];//set avoidance for all
  116.                                                     //bodies    
  117.             }
  118.             else {  // object has zipped off screen
  119.                     //in case of multiple - last one has zipped off screen
  120.                 [self setNextStartTime];
  121.                 currentMultTotal = 1;
  122.                 multDelay = floor(randBetween(objectSpeed * 0.1,
  123.                  (objectSpeed * 0.1) + 10));
  124.                 bodyCount++;
  125.                 if(bodyCount >= animBuilt ){  //complete cycle is done
  126.                     currentCycle++;
  127.                     if(currentCycle > cycles){//done with this module
  128.                     
  129.                         if(!([starsObject isStopping])){
  130.                             if(soundEnabled)
  131.                                 [pwrDownSnd play];
  132.                             [starsObject stopStars];
  133.                             starsStopping = YES;
  134.                         }
  135.                         currentBodyIndex++;
  136.                           if(currentBodyIndex >= totalBodies)
  137.                                currentBodyIndex = 0;
  138.                         cycleStartIndex = currentBodyIndex;
  139.                     }
  140.                     else {
  141.                         currentBodyIndex = cycleStartIndex;
  142.                         bodyCount = 0;
  143.                         [self changeBodyList:currentBodyIndex]; //create body
  144.                     }
  145.                 }
  146.                 else {
  147.                     currentBodyIndex++;
  148.                     if(currentBodyIndex >= totalBodies)
  149.                            currentBodyIndex = 0;
  150.                     [self changeBodyList:currentBodyIndex]; //create body
  151.  
  152.                 }
  153.             }
  154.         }
  155.         else
  156.             nextStartTime--;
  157.     }
  158. }
  159. else{ //stars are stopping
  160.     if(starsStopped){
  161.             PSsetlinewidth(0.0);  //reset
  162.         done = YES;
  163.     }
  164. }
  165. return done;
  166. }
  167.  
  168.  
  169. - setStartInterval: (Slider *)sender;
  170. {
  171.  
  172.     startInterval = [sender intValue];
  173.     nextStartTime = 0;
  174.     return self;
  175.  
  176. }
  177.  
  178. - setNextStartTime
  179. {
  180.     nextStartTime = startInterval;
  181.     return self;
  182. }
  183. - setPwrDownSnd:(Sound *)theSound
  184. {
  185.     pwrDownSnd = theSound;
  186.     return self;
  187. }
  188. - setPwrUpSnd:(Sound *)theSound;
  189. {
  190.     pwrUpSnd = theSound;
  191.     return self;
  192. }
  193.  
  194. - setObjectSpeed: (Slider *)sender
  195. {
  196.  
  197.     objectSpeed =([sender maxValue] + [sender minValue]) - [sender floatValue];
  198.     return self;
  199. }
  200.  
  201. - setBoundsRect:(NXRect *)r
  202. {
  203.  
  204.     bounds.origin.x = r->origin.x;
  205.     bounds.origin.y  = r->origin.y;
  206.     bounds.size.width = r->size.width;
  207.     bounds.size.height = r->size.height;
  208.     
  209.     return self;
  210. }
  211.  
  212.  
  213. - changeBodyList:(int)index
  214. {
  215.  
  216. int ii;
  217. int total;
  218. AvoidStruct avoidStruct;
  219.  
  220.     for(ii=0;ii < 4;ii++)  //init the lastTheta array
  221.         lastTheta[ii] = -1;
  222.         
  223.     total = floor(randBetween(2,MAXMULTBODY));
  224.     
  225.     if([bodyList count]){
  226.         [bodyList freeObjects];
  227.     }
  228.  
  229.     [avoidStorage empty];
  230.     isMult = ((ImageStruct *)[tiffStorage elementAt:
  231.         index])->isMult;
  232.         
  233.     avoidStruct.avoid.origin.x = 0.0;
  234.     avoidStruct.avoid.origin.y = 0.0;
  235.     avoidStruct.avoid.size.width = 0.0;    
  236.     avoidStruct.avoid.size.height = 0.0;
  237.  
  238.     if(isMult){
  239.         for(ii=0;ii < total;ii++){
  240.             currentBody = [self createBody:index];
  241.             [currentBody setBodyIndex:ii];
  242.             [bodyList addObject:currentBody];
  243.             [avoidStorage addElement:&avoidStruct];
  244.         }
  245.     }
  246.     else{
  247.         currentBody = [self createBody:currentBodyIndex];
  248.         [bodyList addObject:currentBody];
  249.         [avoidStorage addElement:&avoidStruct];
  250.  
  251.     }
  252.     
  253.     return self;
  254. }
  255.  
  256.  
  257. - (Body *)createBody:(int)index
  258. {
  259. Body        *body;
  260. float         theta;    //angle of travel for new body
  261. float         multObjectSpeed;
  262.  
  263.     body = [[Body alloc] init];
  264.     [body setAvoidStorage:avoidStorage];
  265.  
  266.     [body setImageList:((ImageStruct *)[tiffStorage
  267.      elementAt:index])->imageList];
  268.      
  269.     [body setNumberOfFrames];
  270.     [body setBoundsRect:(NXRect *)&bounds]; //must be done after setCellSize
  271.     
  272.     if(isMult){
  273.         multObjectSpeed = objectSpeed + floor(randBetween(0,10));
  274.         [body setObjectSpeed:multObjectSpeed];
  275.         theta = [self genUniqueTheta];  //make sure mult objects stay clear
  276.                                         //of each other
  277.  
  278.     }
  279.     else{
  280.         [body setObjectSpeed:objectSpeed];
  281.         theta = randBetween(0,(2*PI));
  282.     }
  283.     [body setAngle:theta];
  284.     [body setStarsOutlet: (id)starsObject];
  285.     return(body);
  286. }
  287.  
  288. - starsStopped
  289. {
  290.     starsStopped = YES;
  291.     return self;
  292. }
  293. - setStarsOutlet:(id)starsOutlet;
  294. {
  295.     starsObject = starsOutlet;
  296.     return self;
  297. }// just a prototype - not used in this module
  298. - setStarSpeed:sender
  299. {
  300.     return self;     
  301. }
  302.  
  303. //The idea here was that individual modules could decide
  304. //how to interpret the slider value
  305. // if you only want this module to do one pass etc.
  306.  
  307. - (int)setCycleValue:(int)value;
  308. {
  309. int mutiplier;
  310.     // since this module is interesting make it 5 times the slider value
  311.     // could be zero
  312.     
  313.     mutiplier = 5;
  314.     if(!value)
  315.         value = 1;
  316.     else
  317.         value *= mutiplier;
  318.     cycles = value;
  319.     currentCycle = 1;
  320.     return mutiplier;
  321. }
  322.  
  323. - windowSizeChanged
  324. {
  325.     if(currentBody){  //if one exists
  326.  
  327.         [self setNextStartTime];
  328.         //[bodyList freeObjects];
  329.         //printf("window size changed bodylist has %d elements\n",
  330.         //[bodyList count]);
  331.         
  332.         currentMultTotal = 1;
  333.         currentBody = nil;
  334.         [self changeBodyList:currentBodyIndex];
  335.     }
  336.  
  337.     return self;
  338. }
  339. - freeResources
  340. {
  341.     [tiffManagerObject freeTiffs];
  342.     if ([bodyList count]){
  343.         [bodyList freeObjects];
  344.     }
  345.     return self;
  346. }
  347. // just a prototype - sound isn't used in this module
  348. - setSoundEnabled:(BOOL)enabled
  349. {
  350.     soundEnabled = enabled;
  351.     return self;
  352. }
  353.  
  354. //for each 4 in a row - make sure random theta is
  355. // 40 degrees from any of the others    
  356. - (float)genUniqueTheta
  357. {
  358. int ii;
  359. int maxTest = 4;
  360. float theta;
  361. BOOL thetaOK = NO;
  362.  
  363.     theta = randBetween(0,(2*PI));
  364.  
  365.     while(!thetaOK){
  366.         thetaOK = YES;
  367.         for(ii = 0;ii < maxTest;ii++){
  368.             if(lastTheta[ii] < 0)
  369.                 continue;
  370.                 //.69 = 40 degrees
  371.             if(theta > (lastTheta[ii] - .69) && theta < (lastTheta[ii] + .69)){
  372.                 thetaOK = NO;
  373.                 theta = randBetween(0,(2*PI));
  374.             }
  375.         }  
  376.     }
  377.     for(ii = 1;ii < maxTest;ii++){
  378.         lastTheta[ii-1] = lastTheta[ii];
  379.     }
  380.     lastTheta[ii-1] = theta;
  381.  
  382.     
  383.     
  384.     return theta;
  385. }
  386. @end
  387.